package com.spzx.cart.service.impl;

import com.spzx.cart.api.domain.CartInfo;
import com.spzx.cart.service.ICartService;
import com.spzx.common.core.constant.HttpStatus;
import com.spzx.common.core.constant.SecurityConstants;
import com.spzx.common.core.context.SecurityContextHolder;
import com.spzx.common.core.domain.R;
import com.spzx.common.core.exception.ServiceException;
import com.spzx.product.api.RemoteProductService;
import com.spzx.product.api.domain.ProductSku;
import com.spzx.product.api.domain.vo.SkuPrice;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.BoundHashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.yaml.snakeyaml.events.Event;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;

@Service
@Slf4j
public class CartServiceImpl implements ICartService {

    @Autowired
    RedisTemplate redisTemplate;

    @Autowired
    private RemoteProductService remoteProductService;

    //把获取外层key的代码提取成一个方法
    private String getCartKey(Long userId){
        //若依封装的工具类
        //大key,外层key
        String cartKey = "user:cart:" + userId;
        return cartKey;
    }

    @Override
    public void addToCart(Long skuId, Integer skuNum) {
        Long userId = SecurityContextHolder.getUserId();

        String cartKey = getCartKey(userId);

        //小key,内层key
        String hashKey = skuId.toString();

        BoundHashOperations boundHashOperations = redisTemplate.boundHashOps(cartKey);

        if (boundHashOperations.hasKey(hashKey)) {
            //走到这说明已经添加过,修改数量即可
            CartInfo cartInfo = (CartInfo) boundHashOperations.get(hashKey);

            //商品的数量不能超过99
            int total = cartInfo.getSkuNum() + skuNum;

            //设置边界值
            int right = 99;

            total = total > right ? right : total;

            cartInfo.setSkuNum(total);
            cartInfo.setUpdateTime(new Date());

            boundHashOperations.put(hashKey,cartInfo);
        } else {
            //走到这执行新增操作
            //总商品类数不能超过50

            Long size = boundHashOperations.size();

            if (++size > 50){
                throw new ServiceException("不能再添加商品了");
            }


            //小val,内层value
            //用封装好的对象做小value
            CartInfo cartInfo = new CartInfo();

            cartInfo.setUserId(userId);

            cartInfo.setSkuId(skuId);

            cartInfo.setSkuNum(1);//首次添加.默认值为1
            cartInfo.setCreateTime(new Date());

            //想要封装剩下的属性,就需要远程调用(fegin) 根据skuId远程调用商品微服务,来查询ProductSku对象
            R<ProductSku> productSkuR = remoteProductService.getProductSku(skuId, SecurityConstants.INNER);

            if (productSkuR.getCode() == HttpStatus.ERROR) {//500表示服务器降级处理了
                throw new ServiceException(productSkuR.getMsg());
            }

            ProductSku productSku = productSkuR.getData();

            cartInfo.setCartPrice(productSku.getSalePrice());
            cartInfo.setSkuPrice(productSku.getSalePrice());
            cartInfo.setThumbImg(productSku.getThumbImg());
            cartInfo.setSkuName(productSku.getSkuName());

            //cartInfo.setIsChecked(1); 默认选中

            //内层key和内层value共同组成了外层的大value
            boundHashOperations.put(hashKey, cartInfo);
        }
    }

    @Override
    public List<CartInfo> carList() {
        
        //要获取购物车数据,其实就是从缓存中获取存入的商品数据
        //1.首先获取外层key
        Long userId = SecurityContextHolder.getUserId();
        String cartKey = getCartKey(userId);

        //2.从redis中获取到val集合
        BoundHashOperations boundHashOperations = redisTemplate.boundHashOps(cartKey);

        List<CartInfo> cartInfoList = boundHashOperations.values();

        if (CollectionUtils.isEmpty(cartInfoList)){
            return new ArrayList<>();
        }

        //3.获取skuId列表,用于批量查询最新的售价
        List<Long> skuIdList = new ArrayList<>();
        for (CartInfo cartInfo : cartInfoList) {
            skuIdList.add(cartInfo.getSkuId());
        }

        //4.远程调用product微服务,用来批量查询最新价格
        R<HashMap<Long, SkuPrice>> skuPriceListR = remoteProductService.getSkuPriceList(skuIdList, SecurityConstants.INNER);

        if (skuPriceListR.getCode() == HttpStatus.ERROR){
            throw new ServiceException(skuPriceListR.getMsg());
        }

        HashMap<Long, SkuPrice> skuPriceMap = skuPriceListR.getData();


        //5.将获取到的最新售价同步到实体类中
        for (CartInfo cartInfo : cartInfoList) {
            cartInfo.setSkuPrice(skuPriceMap.get(cartInfo.getSkuId()).getSalePrice());
        }

        return cartInfoList;
    }

    @Override
    public void deleteCart(Long skuId) {
        //删除方法比较简单,直接在缓存中删除相应的
        Long userId = SecurityContextHolder.getUserId();

        //获取大key
        String cartKey = getCartKey(userId);

        //获取小key
        String hashKey = skuId.toString();


        BoundHashOperations boundHashOperations = redisTemplate.boundHashOps(cartKey);

        boundHashOperations.delete(hashKey);

    }

    @Override
    public void checkCart(Long skuId,Integer isChecked) {

        //1.从缓存中获取到对应的商品信息
        //获取大key
        Long userId = SecurityContextHolder.getUserId();
        String cartKey = getCartKey(userId);

        //获取小key
        String hashKey = skuId.toString();

        BoundHashOperations boundHashOperations = redisTemplate.boundHashOps(cartKey);

        CartInfo cartInfo = (CartInfo) boundHashOperations.get(hashKey);

        //如果小key不存在,则没必要执行
        if (boundHashOperations.hasKey(hashKey)){
            cartInfo.setIsChecked(isChecked);
            boundHashOperations.put(hashKey,cartInfo);
        }

    }

    @Override
    public void allCheckCart(Integer isChecked) {
        //1.从缓存中获取到对应的商品信息
        //获取大key
        Long userId = SecurityContextHolder.getUserId();
        String cartKey = getCartKey(userId);

        BoundHashOperations<String, String, CartInfo> boundHashOperations = redisTemplate.boundHashOps(cartKey);

        List<CartInfo> cartInfoList = boundHashOperations.values();

        for (CartInfo cartInfo : cartInfoList) {
            cartInfo.setIsChecked(isChecked);

            //更新缓存
            boundHashOperations.put(cartInfo.getSkuId().toString(),cartInfo);
        }


    }

    @Override
    public void clearCart() {

        //获取大key
        Long userId = SecurityContextHolder.getUserId();
        String cartKey = getCartKey(userId);

        redisTemplate.delete(cartKey);
    }

    @Override
    public List<CartInfo> getCartCheckedList(Long userId) {
        //本方法的需求是查询出购物车中选中的商品并返回

        ArrayList<CartInfo> cartInfoList = new ArrayList<>();

        //首先获取大key
        String cartKey = getCartKey(userId);

        BoundHashOperations<String,String,CartInfo> boundHashOperations = redisTemplate.boundHashOps(cartKey);

        List<CartInfo> cartInfos = boundHashOperations.values();

        if (CollectionUtils.isEmpty(cartInfos)){
            return cartInfoList;
        }

        for (CartInfo cartInfo : cartInfos) {
            if (cartInfo.getIsChecked().intValue() == 1){
                cartInfoList.add(cartInfo);
            }
        }

        return cartInfoList;
    }

    @Override
    public Boolean updateCartPrice(Long userId) {

        //在结算的时候如果发现价格不是最新的就拒绝下单,然后更新购物车的价格

        //不管要干什么肯定要先把大key获取出来,而且根据业务需求,参数直接给返回了userId肯定是要更新刚才下单失败的用户的缓存
        String cartKey = getCartKey(userId);

        //最新的价格怎么拿,就直接从数据库查,这个接口需要写吗?
        //不,在产品微服务中已经写过了获取商品最新价格的代码,所以直接远程调用就行

        //因为要传的参数是产品id的集合,这个集合从哪里来,从缓存中来

        //先new一个集合用来接收skuId
        ArrayList<Long> skuIdList = new ArrayList<>();

        BoundHashOperations<String, String, CartInfo> boundHashOperations = redisTemplate.boundHashOps(cartKey);

        List<CartInfo> cartInfoList = boundHashOperations.values();

        //从缓存查出来的商品集合中获取到选中的商品的skuId,并存入到集合中
        if (!CollectionUtils.isEmpty(cartInfoList)){
            for (CartInfo cartInfo : cartInfoList) {
                if (cartInfo.getIsChecked().intValue() == 1){
                    skuIdList.add(cartInfo.getSkuId());
                }
            }
        }

        //远程调用查出商品的最新价格
        R<HashMap<Long, SkuPrice>> skuPriceListR = remoteProductService.getSkuPriceList(skuIdList, SecurityConstants.INNER);

        if (skuPriceListR.getCode() == 500){
            throw new ServiceException(skuPriceListR.getMsg());
        }

        HashMap<Long, SkuPrice> skuPriceHashMap = skuPriceListR.getData();

        //遍历集合给选中的商品更新价格
        for (CartInfo cartInfo : cartInfoList) {
            if (cartInfo.getIsChecked().intValue() == 1){
                cartInfo.setCartPrice(skuPriceHashMap.get(cartInfo.getSkuId()).getSalePrice());
                cartInfo.setSkuPrice(skuPriceHashMap.get(cartInfo.getSkuId()).getSalePrice());
                boundHashOperations.put(cartInfo.getSkuId().toString(), cartInfo);
            }
        }


        return true;
    }

    @Override
    public Boolean deleteCartCheckedList(Long userId) {

        //下单成功要结算后直接删除选中的购物车中的数据

        //获取大key
        String cartKey = getCartKey(userId);

        BoundHashOperations<String,String,CartInfo> boundHashOperations = redisTemplate.boundHashOps(cartKey);

        List<CartInfo> cartInfoList = boundHashOperations.values();

        //遍历集合,查出来选中的商品
        if (!CollectionUtils.isEmpty(cartInfoList)){
            for (CartInfo cartInfo : cartInfoList) {
                if (cartInfo.getIsChecked().intValue() == 1){
                    boundHashOperations.delete(cartInfo.getSkuId().toString());
                }
            }
        }


        return true;
    }
}








